﻿using IceZero.Business.Models;
using IceZero.DataStore;
using IceZero.DataStore.Models;
using NHibernate.Criterion;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IceZero.Business
{
    /// <summary>
    /// 
    /// </summary>
    public class ActionStatisticBusiness : BusinessBase
    {
        private static object _addOperationRecordLock = new();
        /// <summary>
        /// 
        /// </summary>
        public OperationActionDataStore OperationActionDataStore { get; }
        /// <summary>
        /// 
        /// </summary>
        public OperationActionComboDataStore OperationActionComboDataStore { get; }
        /// <summary>
        /// 
        /// </summary>
        public OperationActionComboUsedDataStore OperationActionComboUsedDataStore { get; }
        /// <summary>
        /// 
        /// </summary>
        public OperationRecordDataStore OperationRecordDataStore { get; }

        /// <summary>
        /// 
        /// </summary>
        public OperationStatisticRecordDataStore OperationStatisticRecordDataStore { get; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="operationActionDataStore"></param>
        /// <param name="operationActionComboDataStore"></param>
        /// <param name="operationActionComboUsedDataStore"></param>
        /// <param name="operationRecordDataStore"></param>
        /// <param name="operationStatisticRecordDataStore"></param>
        public ActionStatisticBusiness(OperationActionDataStore operationActionDataStore,
            OperationActionComboDataStore operationActionComboDataStore,
            OperationActionComboUsedDataStore operationActionComboUsedDataStore,
            OperationRecordDataStore operationRecordDataStore,
            OperationStatisticRecordDataStore operationStatisticRecordDataStore
            )
        {
            OperationActionDataStore = operationActionDataStore;
            OperationActionComboDataStore = operationActionComboDataStore;
            OperationActionComboUsedDataStore = operationActionComboUsedDataStore;
            OperationRecordDataStore = operationRecordDataStore;
            OperationStatisticRecordDataStore = operationStatisticRecordDataStore;
        }

        /// <summary>
        /// 添加统计信息
        /// </summary>
        /// <param name="actionComboId">动作组id</param>
        /// <param name="actionId">动作id</param>
        /// <param name="targetId">目标id</param>
        /// <param name="targetType">目标类型</param>
        /// <param name="userId">用户id,记录当前动作执行人</param>
        /// <param name="targetOwnerId">目标所属id,默认挂载在unknown上，如果需要统计如某个用户拥有的目标对象如被点赞情况，必须传此参数</param>
        /// <param name="remark">统计记录备注</param>
        public void AddOperationRecord(string actionComboId, string actionId, string targetId, string targetType, string userId, string targetOwnerId = "unknown", string remark = "")
        {
            if (string.IsNullOrWhiteSpace(actionComboId))
            {
                throw new IceZeroArgumentException(nameof(actionComboId));
            }

            if (string.IsNullOrWhiteSpace(actionId))
            {
                throw new IceZeroArgumentException(nameof(actionId));
            }

            if (string.IsNullOrWhiteSpace(targetId))
            {
                throw new IceZeroArgumentException(nameof(targetId));
            }

            if (string.IsNullOrWhiteSpace(targetType))
            {
                throw new IceZeroArgumentException(nameof(targetType));
            }

            var actionComboInfo = OperationActionComboDataStore.QueryById(actionComboId);
            if (actionComboInfo == null)
            {
                throw new IceZeroBusinessException(ActionStatisticExceptionCode.GetMsg(ActionStatisticExceptionCode.AC001), ActionStatisticExceptionCode.AC001);
            }
            var isActionMatch = false;
            if (actionComboInfo.IsMutexAction)
            {
                isActionMatch = actionComboInfo.PositiveActionId == actionId || actionComboInfo.OppositeActionId == actionId;
            }
            else
            {
                isActionMatch = actionComboInfo.PositiveActionId == actionId;
            }

            if (!isActionMatch)
            {
                throw new IceZeroBusinessException(ActionStatisticExceptionCode.GetMsg(ActionStatisticExceptionCode.AC002), ActionStatisticExceptionCode.AC002);
            }

            var isMutexAction = actionComboInfo.IsMutexAction;
            var isLoop = actionComboInfo.IsLoop;

            //统计目标被执行某种动作的正向行为次数，如点赞
            var targetConditionKey = $"{targetType}|{targetId}|{actionComboId}";
            var targetConditionDesc = "TargetType|TargetId|ActionComboId";
            //统计用户执行了某种正向动作的次数
            var userConditionKey = $"{userId}|{actionComboId}";
            var userConditionDesc = "CreatorId|ActionComboId";
            //统计用户所属的所有对象被执行了某种正向动作的次数
            var userBeConditionKey = $"{targetOwnerId}|Be|{actionComboId}";
            var userBeConditionDesc = "TargetOwnerId|Be|ActionComboId";

            //查找是否已存在使用记录
            var actionComboUsed = OperationActionComboUsedDataStore.QueryOne(expressions =>
            {
                expressions.Add(Restrictions.Eq("CreatorId", userId));
                expressions.Add(Restrictions.Eq("TargetId", targetId));
                expressions.Add(Restrictions.Eq("TargetType", targetType));
                expressions.Add(Restrictions.Eq("ActionComboId", actionComboId));
                return expressions;
            });
            lock (_addOperationRecordLock)
            {

                //目标统计信息
                var targetOSR = OperationStatisticRecordDataStore.QueryOne(expressions =>
                {
                    expressions.Add(Restrictions.Eq("ConditionKey", targetConditionKey));
                    return expressions;
                });
                //用户行为统计信息
                var userOSR = OperationStatisticRecordDataStore.QueryOne(expressions =>
                 {
                     expressions.Add(Restrictions.Eq("ConditionKey", userConditionKey));
                     return expressions;
                 });

                //用户所属目标被统计信息
                var userBeOSR = OperationStatisticRecordDataStore.QueryOne(expressions =>
                {
                    expressions.Add(Restrictions.Eq("ConditionKey", userBeConditionKey));
                    return expressions;
                });

                //如果不存在，先创建统计key
                if (targetOSR == null)
                {
                    targetOSR = new OperationStatisticRecord()
                    {
                        ConditionKey = targetConditionKey,
                        ConditionDesc = targetConditionDesc,
                        ActionComboId = actionComboId,
                        Count = 0
                    };
                    var id = OperationStatisticRecordDataStore.Save<string>(targetOSR);
                }
                //如果不存在，先创建统计key
                if (userOSR == null)
                {
                    userOSR = new OperationStatisticRecord()
                    {
                        ConditionKey = userConditionKey,
                        ConditionDesc = userConditionDesc,
                        ActionComboId = actionComboId,
                        Count = 0
                    };
                    var id = OperationStatisticRecordDataStore.Save<string>(userOSR);
                }

                //如果不存在，先创建统计key
                if (userBeOSR == null)
                {
                    userBeOSR = new OperationStatisticRecord()
                    {
                        ConditionKey = userBeConditionKey,
                        ConditionDesc = userBeConditionDesc,
                        ActionComboId = actionComboId,
                        Count = 0
                    };
                    var id = OperationStatisticRecordDataStore.Save<string>(userBeOSR);
                }

                //循环不互斥，则是不断的添加
                if (isLoop)
                {
                    //循环，首次则一定是正向行为
                    if (actionComboUsed == null)
                    {
                        if (actionComboInfo.PositiveActionId != actionId)
                        {
                            throw new IceZeroBusinessException(ActionStatisticExceptionCode.GetMsg(ActionStatisticExceptionCode.AC003), ActionStatisticExceptionCode.AC003);
                        }
                        OperationActionComboUsedDataStore.Save<string>(new OperationActionComboUsed()
                        {
                            ActionComboId = actionComboId,
                            TargetId = targetId,
                            TargetType = targetType,
                            IsPositive = true,
                            CreatorId = userId,
                            UpdaterId = userId,
                            TargetOwnerId = targetOwnerId
                        });
                        targetOSR.Count += 1;
                        userOSR.Count += 1;
                        userBeOSR.Count += 1;
                        OperationStatisticRecordDataStore.Update(targetOSR);
                        OperationStatisticRecordDataStore.Update(userOSR);
                        OperationStatisticRecordDataStore.Update(userBeOSR);
                    }
                    else
                    {
                        //获取当前行为是否是正向的
                        var isPositive = actionComboUsed.IsPositive;
                        //如果是互斥，则更改互斥状态
                        if (isMutexAction)
                        {
                            if (isPositive && actionComboInfo.PositiveActionId == actionId)
                            {
                                throw new IceZeroBusinessException(ActionStatisticExceptionCode.GetMsg(ActionStatisticExceptionCode.AC004), ActionStatisticExceptionCode.AC004);
                            }

                            if (!isPositive && actionComboInfo.OppositeActionId == actionId)
                            {
                                throw new IceZeroBusinessException(ActionStatisticExceptionCode.GetMsg(ActionStatisticExceptionCode.AC004), ActionStatisticExceptionCode.AC004);
                            }
                            //对存在的可循环的行为进行变更
                            actionComboUsed.IsPositive = !isPositive;
                        }
                        if (actionComboUsed.IsPositive)
                        {
                            targetOSR.Count += 1;
                            userOSR.Count += 1;
                            userBeOSR.Count += 1;
                        }
                        else
                        {
                            targetOSR.Count -= 1;
                            userOSR.Count -= 1;
                            userBeOSR.Count -= 1;
                        }
                        OperationStatisticRecordDataStore.Update(targetOSR);
                        OperationStatisticRecordDataStore.Update(userOSR);
                        OperationStatisticRecordDataStore.Update(userBeOSR);

                        actionComboUsed.UpdateTime = DateTime.Now;
                        actionComboUsed.UpdaterId = userId;
                        OperationActionComboUsedDataStore.Update(actionComboUsed);
                    }
                    //记录表始终是添加新纪录
                    OperationRecordDataStore.Save(new OperationRecord()
                    {
                        ActionComboId = actionComboId,
                        CreatorId = userId,
                        UpdaterId = userId,
                        CurrentActionId = actionId,
                        TargetId = targetId,
                        TargetType = targetType,
                        TargetOwnerId = targetOwnerId,
                        Remark = remark,
                    });
                }
                else
                {
                    //不循环，则为只执行一次，因此不限制是否互斥
                    if (actionComboUsed == null)
                    {
                        actionComboUsed = new OperationActionComboUsed()
                        {
                            ActionComboId = actionComboId,
                            TargetId = targetId,
                            TargetType = targetType,
                            IsPositive = actionComboInfo.PositiveActionId == actionId,
                            CreatorId = userId,
                            UpdaterId = userId,
                            TargetOwnerId = targetOwnerId
                        };
                        var id = OperationActionComboUsedDataStore.Save<string>(actionComboUsed);
                        actionComboUsed.Id = id;

                        if (actionComboUsed.IsPositive)
                        {
                            targetOSR.Count += 1;
                            userOSR.Count += 1;
                            userBeOSR.Count += 1;
                        }
                        OperationStatisticRecordDataStore.Update(targetOSR);
                        OperationStatisticRecordDataStore.Update(userOSR);
                        OperationStatisticRecordDataStore.Update(userBeOSR);

                        OperationRecordDataStore.Save(new OperationRecord()
                        {
                            ActionComboId = actionComboId,
                            CreatorId = userId,
                            UpdaterId = userId,
                            CurrentActionId = actionId,
                            TargetId = targetId,
                            TargetType = targetType,
                            TargetOwnerId = targetOwnerId,
                            Remark = remark,
                        });
                    }
                    else
                    {
                        throw new IceZeroBusinessException(ActionStatisticExceptionCode.GetMsg(ActionStatisticExceptionCode.AC005), ActionStatisticExceptionCode.AC005);
                    }
                }
            }
        }

        /// <summary>
        /// 添加统计信息
        /// </summary>
        /// <param name="args">参数对象</param>
        public void AddOperationRecord(AddOperationRecordArgs args)
        {
            AddOperationRecord(args.ActionComboId, args.ActionId, args.TargetId, args.TargetType, args.UserId, args.TargetOwnerId, args.Remark);
        }

        /// <summary>
        /// 批量添加统计信息
        /// </summary>
        /// <param name="argsList">参数对象列表</param>
        public void BatchAddOperationRecord(List<AddOperationRecordArgs> argsList)
        {
            BatchAction(argsList, AddOperationRecord);
        }

        /// <summary>
        /// 获取所有的动作组合列表信息
        /// </summary>
        public List<OperationActionCombo> GetActionCombos()
        {
            var list = OperationActionComboDataStore.QueryAll();
            return list;
        }

        /// <summary>
        /// 获取目标统计信息
        /// </summary>
        /// <param name="targetId">目标id</param>
        /// <param name="targetType">目标类型</param>
        /// <param name="userId">用户id，用于判断当前用户是否执行过某些行为</param>
        public List<GetTargetStatisticInfoItemResult> GetTargetStatisticInfo(string targetId, string targetType, string userId)
        {
            if (string.IsNullOrWhiteSpace(targetId))
            {
                throw new IceZeroArgumentException(nameof(targetId));
            }
            var list = new List<GetTargetStatisticInfoItemResult>();
            var osrList = OperationStatisticRecordDataStore.QueryListBy(expressions =>
            {
                expressions.Add(Restrictions.Like("ConditionKey", $"{targetType}|{targetId}", MatchMode.Start));
                expressions.Add(Restrictions.Eq("ConditionDesc", "TargetType|TargetId|ActionComboId"));
                return expressions;
            });
            foreach (var osrItem in osrList)
            {
                var actionComboId = osrItem.ActionComboId;
                var actionComboInfo = OperationActionComboDataStore.QueryOne("Id", actionComboId);
                var positiveActionInfo = OperationActionDataStore.QueryById(actionComboInfo.PositiveActionId);
                var actionComboUsedInfo = OperationActionComboUsedDataStore.QueryOne(expressions =>
                {
                    expressions.Add(Restrictions.Eq("CreatorId", userId));
                    expressions.Add(Restrictions.Eq("TargetId", targetId));
                    expressions.Add(Restrictions.Eq("TargetType", targetType));
                    expressions.Add(Restrictions.Eq("ActionComboId", actionComboId));
                    return expressions;
                });
                var isPositive = false;
                var hasDoneAction = false;
                if (actionComboUsedInfo != null)
                {
                    hasDoneAction = true;
                    isPositive = actionComboUsedInfo.IsPositive;
                }

                list.Add(new GetTargetStatisticInfoItemResult()
                {
                    ActionComboId = actionComboId,
                    ActionId = positiveActionInfo.Id,
                    ActionCode = positiveActionInfo.ActionCode,
                    IsDonePositive = isPositive,
                    HasDoneAction = hasDoneAction,
                    ActionCount = osrItem.Count,
                });
            }
            return list;
        }

        /// <summary>
        /// 获取目标统计信息
        /// </summary>
        /// <param name="args">参数对象</param>
        /// <returns></returns>
        public List<GetTargetStatisticInfoItemResult> GetTargetStatisticInfo(GetTargetStatisticInfoArgs args)
        {
            return GetTargetStatisticInfo(args.TargetId, args.TargetType, args.UserId);
        }

        /// <summary>
        /// 批量获取目标对象的统计信息
        /// </summary>
        /// <param name="argsList">参数对象列表</param>
        public List<List<GetTargetStatisticInfoItemResult>> BatchGetTargetStatisticInfo(List<GetTargetStatisticInfoArgs> argsList)
        {
            return BatchAction(argsList, GetTargetStatisticInfo);
        }

        /// <summary>
        /// 获取用户主动行为统计信息
        /// </summary>
        /// <param name="userId">统计用户的id</param>
        /// <returns></returns>
        public List<GetUserStatisticInfoItemResult> GetUserStatisticInfo(string userId)
        {
            var list = new List<GetUserStatisticInfoItemResult>();
            var osrList = OperationStatisticRecordDataStore.QueryListBy(expressions =>
            {
                expressions.Add(Restrictions.Like("ConditionKey", $"{userId}|", MatchMode.Start));
                expressions.Add(Restrictions.Eq("ConditionDesc", "CreatorId|ActionComboId"));
                return expressions;
            });
            foreach (var osrItem in osrList)
            {
                var actionComboId = osrItem.ActionComboId;
                var actionComboInfo = OperationActionComboDataStore.QueryOne("Id", actionComboId);
                var positiveActionInfo = OperationActionDataStore.QueryById(actionComboInfo.PositiveActionId);

                list.Add(new GetUserStatisticInfoItemResult()
                {
                    ActionComboId = actionComboId,
                    ActionId = positiveActionInfo.Id,
                    ActionCode = positiveActionInfo.ActionCode,
                    ActionCount = osrItem.Count,
                });
            }
            return list;
        }

        /// <summary>
        /// 批量获取用户主动行为统计信息
        /// </summary>
        /// <param name="userIds">统计用户的id列表</param>
        /// <returns></returns>
        public List<List<GetUserStatisticInfoItemResult>> BatchGetUserStatisticInfo(List<string> userIds)
        {
            return BatchAction(userIds, GetUserStatisticInfo);
        }

        /// <summary>
        /// 获取目标拥有人被执行正向行为统计信息
        /// </summary>
        /// <param name="targetOwnerId">目标拥有人id</param>
        /// <returns></returns>
        public List<GetTargetOwnerStatisticInfoItemResult> GetTargetOwnerStatisticInfo(string targetOwnerId = "unknown")
        {
            var list = new List<GetTargetOwnerStatisticInfoItemResult>();
            var osrList = OperationStatisticRecordDataStore.QueryListBy(expressions =>
            {
                expressions.Add(Restrictions.Like("ConditionKey", $"{targetOwnerId}|Be|", MatchMode.Start));
                expressions.Add(Restrictions.Eq("ConditionDesc", "TargetOwnerId|Be|ActionComboId"));
                return expressions;
            });
            foreach (var osrItem in osrList)
            {
                var actionComboId = osrItem.ActionComboId;
                var actionComboInfo = OperationActionComboDataStore.QueryOne("Id", actionComboId);
                var positiveActionInfo = OperationActionDataStore.QueryById(actionComboInfo.PositiveActionId);

                list.Add(new GetTargetOwnerStatisticInfoItemResult()
                {
                    ActionComboId = actionComboId,
                    ActionId = positiveActionInfo.Id,
                    ActionCode = positiveActionInfo.ActionCode,
                    ActionCount = osrItem.Count,
                });
            }
            return list;
        }

        /// <summary>
        /// 批量获取目标拥有人被执行正向行为统计信息
        /// </summary>
        /// <param name="targetOwnerIds">目标拥有人id列表</param>
        /// <returns></returns>
        public List<List<GetTargetOwnerStatisticInfoItemResult>> BatchGetTargetOwnerStatisticInfo(List<string> targetOwnerIds)
        {
            return BatchAction(targetOwnerIds, GetTargetOwnerStatisticInfo);
        }
    }
}
